#ifndef INFIX2SUFFIX_H
#define INFIX2SUFFIX_H

#include "Platform.h"
#include "String2Num.h"
#include "ExprNode.h"
#include "OperatorTable.h"

class Infix2Suffix
{
private:
    String2Num s2n_ter;
    pLib::stack<char> operator_stack;
    pLib::queue<ExprNode> result;

private:
    static constexpr inline bool IsNumOrDot(char c) { return (((c >= '0') && (c <= '9')) || c == '.');}
    static inline bool IsOperator(char c) { return (OperatorTable::Instance()->GetTable().end()) != (OperatorTable::Instance()->GetTable().find(c));}

private:
    bool isLastNum = false;
public:
    void operator<<(char c)
    {
        if(IsNumOrDot(c))
        {
            s2n_ter << c;
            isLastNum = true;
            return;
        }
        if(isLastNum)
        {
            result.push(s2n_ter.GetResult());
            s2n_ter.Clean();
            isLastNum = false;
        }
        if('(' == c)
        {
            operator_stack.push(c);
            return;
        }
        if(')' == c)
        {
            while('(' != operator_stack.top())
            {
                result.push(operator_stack.top());
                operator_stack.pop();
            }
            operator_stack.pop();
        }
        if(IsOperator(c))
        {
            if(operator_stack.empty() || '(' == operator_stack.top())
            {
                operator_stack.push(c);
                return;
            }
            OperatorTable::Priority inP = OperatorTable::Instance()->GetTable().find(c)->second.priority;
            OperatorTable::Priority topP = OperatorTable::Instance()->GetTable().find(operator_stack.top())->second.priority;
            while (topP > inP)
            {
                result.push(operator_stack.top());
                operator_stack.pop();
                if(operator_stack.empty() || '(' == operator_stack.top())
                {
                    operator_stack.push(c);
                    return;
                }
                topP = OperatorTable::Instance()->GetTable().find(operator_stack.top())->second.priority;
            }
            operator_stack.push(c);
            return;
        }
        if('=' == c)
        {
            for(; !operator_stack.empty(); operator_stack.pop())
            {
                result.push(operator_stack.top());
            }
            return;
        }
    }
    inline void SetString(const std::string& s)
    {
        for(auto i : s)
            operator<<(i);
    }
    inline pLib::queue<ExprNode>& GetResult() { return result; }
};


#endif //INFIX2SUFFIX_H
